home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-06-25 | 7.5 KB | 386 lines | [TEXT/MPS ] |
- ******************************************************************************
- *
- * local pointer checker -- Version 3.0
- *
- * Copyright (C) 1989-1990 by Apple Computer.
- * Written by Eric Soldan.
- *
- * Developer Technical Support Apple II Sample Code
- *
- ******************************************************************************
-
- case on
-
- rtlStkDepth equ 50 ;You may need to make this bigger.
-
- ******************************************************************************
-
- * These functions are to help detect usage of C pointers and handles that are
- * not initialized. In main(), call initPtrCheck(). Do NOT call other
- * functions in main.
- *
- * In other functions, call zapLocals() as the first thing in the function.
- * checkForHit() will automatically be called whenever you exit a function.
- * You can call checkForHit() at any point you want, also. If you have an idea
- * of which function has a pointer problem, but you are not sure where in
- * the function the problem is, you can add some calls to checkForHit().
- * The functions initPtrCheck(), closePtrCheck(), zapLocals(), and
- * checkForHit() can be conditionally set active or inactive with #define
- * statements. This way they can be active when developing, and turned off
- * when making a production version. The calls can be defined to nothing,
- * thus making any reference to them drop out of the object code.
- *
- * So, a C program would use the functions as below:
- *
- * main()
- * {
- * initPtrCheck(_ownerid);
- * /* Your code goes here */
- * closePtrCheck();
- * exit(0);
- * }
- *
- * void someFnCalledByMain(parm1, parm2)
- * unsigned int parm1, parm2;
- * {
- * unsigned int i, j, k;
- * unsigned long theID;
- *
- * zapLocals();
- * /* Your code goes here */
- * checkForHit();
- * }
-
- * Note that zapLocals() needs to be the first code in a function. Also,
- * you can't call zapLocals before you call initPtrCheck(). Given this
- * dependency, you can't call zapLocals in main(). To fix this problem,
- * you may wish to have a nearly empty main(). You may want it to just
- * do the initPtrCheck() and closePtrCheck(), and the code in between
- * simply calls something like main0(), which can have a zapLocals().
-
- ******************
-
- * The return address to exit zapLocals is used to point to the code used to
- * create the stack frame. The stack frame code should look like the below.
- * The values in front are the negative offsets from the return address.
- * (This is why zapLocals() must be the first code in a function.)
-
- * E PHD
- * D TSC
- * C SEC
- * BA9 SBC #$fb
- * 8 TCD
- * 765 ADC #$f0
- * 4 TCS
-
- * 321.0 JSL >zapLocals
-
- ******************************************************************************
-
- include 'm16.memory'
- include 'm16.misctool'
- include 'm16.util2'
-
-
- export initPtrCheck
- initPtrCheck proc
- export ptrCheckHndl, rtlStkPtr, rtlStk, zapval
-
- DefineStack
-
- hndl long ;Must be at 1,s.
- ptr long
-
- dpage word
- retaddr block 3
-
- userid word
-
- phd
-
- pha ;Make space for locals.
- pha
- pha
- pha
- tsc
- tcd
-
- pea 1 ;Get the bank-sized handle.
- lda #0
- sta >rtlStkPtr ;Nothing on "stack" yet.
- pha
- pei userid
- pea $C010
- pha
- pha
- _NewHandle
- bcc @gothndl
-
- lda #0
- sta >ptrCheckHndl ;Flag as no handle.
- sta >ptrCheckHndl+2
- sta >zapval ;"Pattern" is 0.
- sta >$0 ;Point 0-2 to the screen.
- lda #$E100 ;If there is any bad stuff
- sta >$1 ;going on, then it will show
- bra @exit ;on the super-hi-res screen.
- ;This is true only for handles.
- ;Simple pointers will still
- ;store into zpage. Storing
- ;into zpage will, most likely,
- ;cause the system to die.
- ;The best test is when the
- ;system has enough memory to
- ;create the 64k hit-test handle.
-
- @gothndl lda hndl ;Keep the handle, and initialize it.
- sta >ptrCheckHndl
- lda hndl+2
- sta >ptrCheckHndl+2
-
- ldy #2 ;Dereference the handle to get to
- lda [hndl],y ;the bank of memory.
- sta ptr+2
- lda [hndl]
- sta ptr
- lda ptr+2 ;Move byte 2 of bank address into
- xba ;byte 3 also.
- ora ptr+2
- sta >zapval
-
- ldy #0 ;Fill the handle with the bank value,
- @loop sta [ptr],y ;so pointers within the handle end
- iny ;up pointing back into the handle.
- iny
- bne @loop
-
- sta >$0
- sta >$2
-
- @exit pla
- pla
- pla
- pla
-
- pld
- rtl
-
- ptrCheckHndl dc.l 0
- zapval dc.w 0
- rtlStkPtr dc.w 0
- rtlStk ds.b rtlStkDepth*3
-
- endp
-
- ******************
-
- export zapLocals
- zapLocals proc
- export saveRegs, getRegs
- import zapval, rtlStkPtr, rtlStk, checkForHitz
-
- DefineStack
-
- ptr long
-
- dpage word
- retaddr block 3
-
- phd
-
- pha ;Make space for locals.
- pha
- tsc
- tcd
-
- lda retaddr+1 ;Use return address as pointer.
- sta ptr+1
- lda retaddr
- sec
- sbc #$0A
- sta ptr
- lda [ptr] ;sbc value
- tax
- ldy #4
- lda [ptr],y ;adc value
-
- sta ptr
- txa
- sec
- sbc ptr
- beq @exit ;No stack frame at all.
- tax ;Save this to fetch RTL address.
- tay ;Number of bytes to zap.
- dey
- beq @exit ;Just in case.
-
- tsc
- clc
- adc #retaddr+2 ;Point to beginning of stack
- sta ptr ;frame to clobber.
- stz ptr+2
-
- shortm
- lda >zapval ;Pattern to clobber with.
- @loop sta [ptr],y
- dey
- bne @loop
- longm
-
- inx ;Save the return address on rtlStk.
- inx
- txy ;yreg is offset to return address.
- lda >rtlStkPtr
- cmp #rtlStkDepth*3 ;Make sure we aren't overflowing rtlStk.
- bcc @a
- brk #$AA
-
- @a tax
- lda [ptr],y
- sta >rtlStk,x
- iny
- inx
- lda [ptr],y
- sta >rtlStk,x ;Return address now on rtlStk.
- inx
- inx
- txa
- sta >rtlStkPtr ;Save new index into rtlStk.
-
- lda #rtlCheck>>8 ;Put return address of checking
- sta [ptr],y ;routine in place of regular
- dey ;return address.
- lda #rtlCheck-1
- sta [ptr],y
-
- @exit pla
- pla
-
- pld
- rtl
-
- rtlCheck equ * ;This is where we end up when a c
- ;function exits with an rtl.
- jsl saveRegs ;Keep registers for return value for c.
-
- lda >rtlStkPtr ;Get the real return address onto the stack.
- tax
- dex
- dex
- lda >rtlStk,x
- pha ;We pushed middle and hi byte here.
- phb
- pla ;We just pulled the middle byte.
- dex
- lda >rtlStk,x
- pha ;We pushed low and middle byte here, so
- ;we have a full rtl address on stack.
- txa
- sta >rtlStkPtr
- jml checkForHitz
-
- saveRegs sta >keepa ;Keep everything.
- txa
- sta >keepx
- tya
- sta >keepy
- php
- php
- pla
- sta >keepp
- rtl
-
- getRegs lda >keepp
- pha
- lda >keepx
- tax
- lda >keepy
- tay
- lda >keepa
- plp
- plp
- rtl
-
- keepa dc.w 0
- keepx dc.w 0
- keepy dc.w 0
- keepp dc.w 0
-
- endp
-
- ******************
-
- export checkForHit
- checkForHit proc
- export checkForHitz
- import zapval, saveRegs, getRegs
-
- jsl saveRegs
-
- checkForHitz lda >zapval
- beq @exit ;When using zpage as hit
- ;detector, there is nothing
- ;we can check. We just have
- ;to wait until the system
- ;dies a horrible death. This
- ;horrible death should happen
- ;faster when clobbering zpage.
- tax
- and #$FFFE ;So we can go by words.
- tay
- txa
-
- phb
- pha
- plb
- plb
-
- @loop cmp |$0,y
- bne @oops
- iny
- iny
- bne @loop
-
- plb ;Put data bank back.
- @exit jml getRegs
-
- @oops plb
-
- brk #$AB ;Bank is indicated by acc.
- ;Offset into bank that was hit is
- ;in the yreg.
- ;The program can be resumed, but unless
- ;the hit is repaired, the program will
- ;break again.
-
- jml getRegs ;Allow option of continuing from debugger.
-
- endp
-
- ******************
-
- export closePtrCheck
- closePtrCheck proc
- import ptrCheckHndl, zapval
-
- jsl checkForHit ;Let's make sure there were no hits.
-
- lda >zapval
- beq @exit ;No handle to dispose of.
-
- lda >ptrCheckHndl+2
- pha
- lda >ptrCheckHndl
- pha
- _DisposeHandle ;We got rid of what we created.
-
- lda #0
- sta >zapval
-
- @exit rtl
-
- endp
-
- END
-
-